package top.lunarye.support.config;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 优雅关闭线程
 * @author lunar
 * @since 2022-07-18
 */
@Slf4j
@Component
public class ThreadPoolExecutorShutdownDefinition implements ApplicationListener<ContextClosedEvent> {

    private final List<ExecutorService> POOLS = Collections.synchronizedList(new ArrayList<>(12));

    // 线程中的任务在接收到应用关闭信号之后最多可以等待多久就强制终止
    private final long AWAIT_TERMINATION = 20;

    private final TimeUnit TIME_UNIT = TimeUnit.SECONDS;

    public void registryExecutor(ExecutorService executor) { POOLS.add(executor); }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        log.info("容器关闭前关闭线程池，当前需要处理的线程池数量为：{}", POOLS.size());
        if (CollectionUtil.isEmpty(POOLS)) {
            return;
        }

        for (ExecutorService pool : POOLS) {
            pool.shutdown();

            try {
                if (!pool.awaitTermination(AWAIT_TERMINATION, TIME_UNIT)) {
                    if (log.isWarnEnabled()) {
                        log.warn("Timed out while waiting for executor [{}] to terminate", pool);
                    }
                }
            } catch (InterruptedException exception) {
                if (log.isWarnEnabled()) {
                    log.warn("Timed out while waiting for executor [{}] to terminate", pool);
                }
                Thread.currentThread().interrupt();
            }
        }
    }
}
